/******************************************************************************/
#include "stdafx.h"
#include "Main.h"
/******************************************************************************/
Button  local_address_copy, global_address_copy, global_address_resolve, open_storage;
Str     Storage        ="Storage/",          // data storage path
        StorageAccounts=Storage+"Accounts/", //      storage path for accounts
        StorageChars   =Storage+"Chars/";    //      storage path for characters
Traffic traffic; // traffic stats
/******************************************************************************/
static void  LocalAddressCopy   (Ptr=NULL) {ClipSet(Server.addressLocal ().asText());} // copy server local  address to system clipboard
static void GlobalAddressCopy   (Ptr=NULL) {ClipSet(Server.addressGlobal().asText());} // copy server global address to system clipboard
static void GlobalAddressResolve(Ptr=NULL) {        Server.addressGlobal(); global_address_resolve.hide();}  // resolve server global address

static void OpenStorage(Ptr=NULL) {OSLaunch(Storage);} // open data folder storage in system explorer
/******************************************************************************/
Str StorageAccountFile(Str name) {return StorageAccounts+CaseDown(name);} // get account   file path
Str StorageCharFile   (Str name) {return StorageChars   +CaseDown(name);} // get character file path
/******************************************************************************/
static Memc<Str> SkelFiles, AnimFiles, MeshFiles, ObjFiles; 

static void AddFileToLibraries(Str file) // if the file is a common resource then add its name to the containers
{
   Str ext=GetExt(file);
   if( ext=="skel")SkelFiles.add(file);else
   if( ext=="anim")AnimFiles.add(file);else
   if( ext=="mesh")MeshFiles.add(file);else
   if( ext=="obj" ) ObjFiles.add(file);
}
static void AddFileToLibrariesFromDataPath(C Str &file)
{
   AddFileToLibraries(SkipStartPath(file, DataPath()));
}
static void GenerateFileLibraries() // iterate all files from loaded Paks and DataPath and add them to containers
{
   SkelFiles.del();
   AnimFiles.del();
   MeshFiles.del();
    ObjFiles.del();

   REP(Paks.files())AddFileToLibraries(Paks.file(i).fullName());             // add files from Paks
   if(Is(DataPath()))FAll(DataPath(), AddFileToLibrariesFromDataPath, true); // add files from DataPath

   // create 'DL' DataLibrary from containers
   DL.skel.create(SkelFiles, false, true); SkelFiles.del();
   DL.anim.create(AnimFiles, false, true); AnimFiles.del();
   DL.mesh.create(MeshFiles, false, true); MeshFiles.del();
   DL.obj .create( ObjFiles, false, true);  ObjFiles.del();

   DLFile.writeMem(); DL.save(DLFile);
}
/******************************************************************************/
void CreateStorageFolders()
{
   FCreateDirs(Storage        );
   FCreateDirs(StorageAccounts);
   FCreateDirs(StorageChars   );
}
/******************************************************************************/
void InitPre()
{
   App.name("Esenthel MMO Server");
   App.flag=APP_WORK_IN_BACKGROUND|APP_NO_PAUSE_ON_WINDOW_MOVE_SIZE|APP_NO_FX|APP_MINIMIZABLE;
#ifdef DEBUG
   App.flag|=APP_MEM_LEAKS|APP_BREAKPOINT_ON_ERROR;
#endif
   D.sync(true).shadowMode(SHADOW_NONE);
   Renderer.type(RT_SIMPLE);

#ifdef DEBUG
   DataPath("Data"); // please use only this line
#else
   #include "../Paks.add(data.pak).cpp" // please ignore this line and always use the one above
#endif
   Paks.add("engine.pak");
}
Bool Init()
{
   DefaultTextStyle.color =BLACK;
   DefaultTextStyle.shadow=0;

   // server shouldn't load client specific data, use dummies to preserve object paths
   Skeletons .mode(CACHE_DUMMY_NULL);
   Animations.mode(CACHE_DUMMY_NULL);
   Images    .mode(CACHE_DUMMY_NULL);
   Materials .mode(CACHE_DUMMY_NULL);
   Meshes    .mode(CACHE_DUMMY_NULL);
   PhysBodies.mode(CACHE_DUMMY_NULL);

   LogN(S+"\r\nServerStart: "+DateTime().getLocal().asText(true)+"\r\n");

   GenerateFileLibraries();
   CreateStorageFolders ();
   if(!Server.create())Exit("Can't create Server TCP Socket");

   // Add Gui Controls
   Gui+= local_address_copy   .create(Rect_C(0.8f, 0.9f, 0.3f, 0.09f), "Copy"   ).func( LocalAddressCopy   ).desc(  "Local Address (Local IP) is the address visible in the Local Network.\nYou can use it to connect with other computers in your network.");
   Gui+=global_address_copy   .create(Rect_C(0.8f, 0.8f, 0.3f, 0.09f), "Copy"   ).func(GlobalAddressCopy   ).desc("Global Address (Public IP) is the address visible in the Global Network.\n\nYou must use it if you want to connect with computers\nwhich are not located in your network.");
   Gui+=global_address_resolve.create(Rect_C(0.8f, 0.8f, 0.3f, 0.09f), "Resolve").func(GlobalAddressResolve).desc("Global Address (Public IP) is the address visible in the Global Network.\n\nYou must use it if you want to connect with computers\nwhich are not located in your network.\n\nResolving Public IP address requires connecting to external websites.");

   Gui+=open_storage.create(Rect_C(0, -0.9f, 1.1f, 0.15f), "Open Storage Folder").func(OpenStorage);

   return true;
}
void Shut()
{
   Server.del(); // manually delete server and its clients before worlds are deleted
}
/******************************************************************************/
Bool Update()
{
   if(Kb.bp(KB_ESC))return false;

   Gui   .update( );
   Server.update( );
   Time  .wait  (1);

   return true;
}
/******************************************************************************/
void Draw()
{
   D.clear(WHITE);

   // draw debug info
   D.text(0, 0.9f, S+"Local Address: " +Server.addressLocal().asText());
   D.text(0, 0.8f, S+"Global Address: "+(global_address_resolve.hidden() ? Server.addressGlobal().asText() : ""));
   D.text(0, 0.7f, S+"Uptime: "+TimeText(Round(Time.curTime()))+", Libraries Size: "+DLFile.size()+", Clients: "+Server.clients.elms()+" (peak: "+Server.clients_peak+")");

   // draw traffic stats
   I64 sent    =Server.bytesSentTotal    (),
       received=Server.bytesReceivedTotal();
   traffic.update(sent, received);

   D.text(0, 0.6f, S+"Received: "+(received>>10)+" KB (5s Avg: "+TextReal(traffic.receive_speed/1024.0f, 2)+" KB/s), Sent: "+(sent>>10)+" KB (5s Avg: "+TextReal(traffic.send_speed/1024.0f, 2)+" KB/s)");

   // draw gui
   Gui.draw();
}
/******************************************************************************/
